package impl;

import java.math.BigInteger;
import java.util.Calendar;
import java.util.Date;
import java.util.Formatter;

import java.util.Random;

//import api.IPostman;
import api.MessageBoards.MessageBoardsType;
import api.PhasebookToken;
import api.ejb.IAuthenticator;
import api.ejb.IPostman;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;


import org.jboss.logging.Logger;

import p3_entities.Login;
import p3_entities.Messageboard;
import p3_entities.Userprofile;


/**
 * Session Bean implementation class Authenticator
 */
@Stateless(name = "IAuthenticator")
//@TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW)
public class Authenticator implements IAuthenticator {
	@PersistenceContext(unitName = "PhaseBookPU")
	EntityManager em;
	
	@EJB(beanName = "IPostman")
	IPostman postman;

	private static final Logger log = Logger.getLogger(Authenticator.class);


	/**
	 * Default constructor.
	 */
	public Authenticator() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public boolean registerUser(String username, String password) {
		log.info("Executing ---------->");


		Query query = em.createNamedQuery("getUserProfile");
		query.setParameter("email", username);

		Userprofile userProfile = null;
		try {
			userProfile = (Userprofile) query.getSingleResult();
			if (userProfile != null)
				return false;

		} catch (NoResultException e) {

		}

		// Create a new user
		Userprofile user = new Userprofile();
		user.setEmail(username);
		em.persist(user);

		userProfile = (Userprofile) query.getSingleResult();

		// Create a login
		Login login = new Login();
		login.setUserprofile(userProfile);
		login.setPasswordHashed(hash(password));
		login.setLastAccess(new Date());
		em.persist(login);

		log.info("New user created.");
		
		// Create a public user message board
		Messageboard msgBoard = new Messageboard();
		msgBoard.setUserprofile(userProfile);
		msgBoard.setType(MessageBoardsType.PUBLIC.ordinal());
		em.persist(msgBoard);

		// Create a private user message board
		msgBoard = new Messageboard();
		msgBoard.setUserprofile(userProfile);
		msgBoard.setType(MessageBoardsType.PRIVATE.ordinal());
		em.persist(msgBoard);

		
		postman.sendMail(user.getEmail(), "Welcome to PhaseBook!", "Welcome to PhaseBook!\n Your registration was successful");
		
		log.info("<--------------- Done");


		return true;
	}

	@Override
	public PhasebookToken authenticate(String username, String password) {
		log.info("Executing ---------->");


		Query query = em.createNamedQuery("validateUserLoggin");
		query.setParameter("email", username);
		query.setParameter("pass", hash(password));

		Integer userId = (Integer) query.getSingleResult();

		query = em.createNamedQuery("getUserLoggin");
		query.setParameter("email", username);
		Login login = (Login) query.getSingleResult();
		login.setLastAccess(new Date());
		em.persist(login);

		log.info("*** User " + username + " validated with id: "
				+ userId.intValue() + " ***");

		//PhasebookToken token = new PhasebookTokenImpl(userId, 0, generateToken());
		PhasebookToken token = new PhasebookToken();
		token.setUserId(userId.intValue());
		token.setAppId(0);
		token.setToken(generateToken(1, 10));
		
		log.info("Authentication token was generated.");
		
		log.info("<--------------- Done");


		
		return (PhasebookToken) token;
	}
	
	@Override
	public boolean validateAuthenticationToken(String token) {
		log.info("Executing ---------->");


		BigInteger userToken = new BigInteger(token);
		BigInteger nowToken = new BigInteger(generateToken(0,0));
		
		if (nowToken.compareTo(userToken)>0)
			return false;
		log.info("<--------------- Done");

		return true;
	}

	@Override
	public Date getLastLogin(String username) {
		log.info("Executing ---------->");


		Query query = em.createNamedQuery("getUserLogginLastAccess");
		query.setParameter("email", username);
		log.info("<--------------- Done");


		return (Date) query.getSingleResult();
	}

	@Override
	public boolean resetPassword(String username) {
		log.info("Executing ---------->");


		Query query = em.createNamedQuery("getUserLoggin");
		query.setParameter("email", username);

		Login login = (Login) query.getSingleResult();
		String newPass = generateString();
		login.setPasswordHashed(hash(newPass));
		em.persist(login);

		String message = "Hi " + username + "\n\n"
				+ "You performed a password reset.\n" + "The new password is'"
				+ newPass + "'";

		log.info("<--------------- Done");

		return true;
	}

	private String hash(String string) {
		long h = 1125899906842597L; // prime
		int len = string.length();

		for (int i = 0; i < len; i++) {
			h = 31 * h + string.charAt(i);
		}
		return "" + h;
	}

	private String generateString() {
		Random rng = new Random();
		String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
		int length = 8;

		char[] text = new char[length];
		for (int i = 0; i < length; i++) {
			text[i] = characters.charAt(rng.nextInt(characters.length()));
		}
		return new String(text);
	}
	
	private String generateToken(int expirationDay, int expirationMinute) {
		
		Formatter fmt = new Formatter();
		Calendar cal = Calendar.getInstance();
		
		int day = cal.get(Calendar.DATE)+expirationDay;
		int month = cal.get(Calendar.MONTH) + 1;
		int year = cal.get(Calendar.YEAR);
		int hour = cal.get(Calendar.HOUR_OF_DAY);
		int minute = cal.get(Calendar.MINUTE)+expirationMinute;

		fmt.format("%04d%02d%02d%02d%02d", year, month, day, hour, minute);
		
		
		return fmt.toString();
	}
}
